/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com 

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef TRI_THREADS_H_
#define TRI_THREADS_H_

#include <iostream>
#include <pthread.h>

#include "utils.h"
#include "sigslot/sigslot.h"
void* __run_thread_via_pthreads__(void* t);

namespace tri {

/**
 * Runner interface class
 */
class thread_runner {
public:
    /**
     * This method must be overwritten by the base class.
     * It should contain the c++ routines to be
     * executed in the thread
     */
    virtual void run()=0;
};

/**
 * Mutex implementation
 */
class thread_mutex {
public:
    thread_mutex();
    virtual ~thread_mutex();

    /**
     * Lock this mutex
     */
    void lock();

    /**
     * Unlock this mutex
     */
    void unlock();

private:
    pthread_mutex_t mutex;
};

/**
 * Thread implementaion class
 */
class thread : public thread_runner {
public:

    /**
     * Optional runner object. If one is
     * provided ,a call to start() will execute 
     * the runner's run method and not the this.run(); 
     * 
     * @param runner : Optional runner  
     */
    thread();
    virtual ~thread();

    /**
     * @see thread_runner.run()
     */
    virtual void run()=0;

    /**
     * Start the thread if it is not already running.
     * You can checkthis by calling isRunning();
     */
    int start();

    void _run();

    /**
     * Returns true is this thread is still running.
     */
    bool isRunning();

    /**
     * Request that this thread terminate.
     * This will cause request_terminate() to return 
     * true. @see request_terminate()
     */
    void terminate();

    /**
     * Block untill the thread exits.
     */
    void wait_on_exit();

protected:

    /**
     * Returns true if terminate() was called while isRunning()
     * returned true. This should be usd in the run() method
     * to respond to termination requests.
     *  
     */
    bool request_terminate();

private:
    pthread_t _thread_;
    bool is_running;
    void setRunning(bool b);
    bool _terminate;
};

class timeout{
public:    
    timeout();
    virtual ~timeout();
    virtual void on_timeout()=0;
};

class timer : public thread {
public:
    timer(timeout* t =NULL,double sec=1.0);
    virtual ~timer();
    void setTime(double sec);
    void run();
    void reset();
    void stop();
    
    sigslot::signal0<sigslot::multi_threaded_local> TIMEOUT;

private:
    utils::timer _timer;
    timeout* to;
};

}

#endif
